/* Game loop frontend for LOCKJAW, an implementation of the Soviet Mind Game

Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net>

This work is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Original game concept and design by Alexey Pajitnov.
The Software is not sponsored or endorsed by Alexey Pajitnov[player], Elorg,
or The Tetris Company LLC.

*/

package fizzpicks.tetrapulp.tetrapulp;

/**
 * Created by will
 * Date: May 3, 2008 7:57:42 AM
 */
public class LJPlay extends LJPC {

String demoFilename;

void play(final LJView v[], int nPlayers) {
  boolean canceled = false;

  for (int player = 0; player < nPlayers; ++player) {
    final LJField p = v[player].field;
    final LJControl ctl = v[player].control;

    ctl.countdown = 6;
    ctl.presses = 0;

    /* Load replay if needed */
/*
//#if WITH_REPLAY
    if (p.gimmick == LJGM.NONE) {
      ctl.replaySrc = openReplay(demoFilename, p);
      if (ctl.replaySrc == null) {
        return;
      }
      v[player].backDirty.bits = ~0;
      playRedrawScreen(v[player]);
    } else {
      ctl.replaySrc = null;
    }
//#endif
*/
  }
  if (v[0].control.replaySrc == null) {
    for (int player = 0; player < nPlayers; ++player) {
      final LJField p = v[player].field;
      Lockjaw.newGame(p);
      Gimmicks.initGimmicks(p);
      v[player].nLockTimes = 0;
      v[player].hideNext = false;
      updField(v[player], new LJBits(true));
    }
    startingAnimation(v[0]);
    for (int player = 0; player < nPlayers; ++player) {
      v[player].control.lastKeys.clear();
      v[player].control.repressKeys.clear();
      blitField(v[player]);
    }
  }

  int lastTime = getTime();

  while(v[0].field.state != LJState.GAMEOVER && !canceled) {
    if (getTime() == lastTime) {
      yieldCPU();
    }
    canceled |= ljHandleConsoleButtons(v[0]);
    while (getTime() - lastTime > 0) {
      for (int player = 0; player < nPlayers; ++player) {
        final LJField p = v[player].field;
        final LJControl ctl = v[player].control;
        LJInput in = new LJInput();
        int curTime = getTime();

        addKeysToInput(in, readPad(player), p, ctl);

        // when returning from pause, catch up the speed control
        if (curTime - lastTime > 10
            || curTime - lastTime < -10) {
          lastTime = curTime;
        }

        {
          boolean irsAttempted = (p.sounds.contains(LJSND.SPAWN) || p.sounds.contains(LJSND.HOLD))
                             && in.rotation != 0 && ctl.initialRotate != 0;

          // The next line does ALL the game logic.
          LJBits updatedRows = frame(p, in).add(Gimmicks.gimmicks(p, ctl));

          v[player].backDirty.add(updatedRows);
          if (irsAttempted && (p.sounds.contains(LJSND.ROTATE))) {
            p.sounds.add(LJSND.IRS);
          }
        }

        // items is a partly view-based gimmick
        if (p.gimmick == LJGM.ITEMS && (p.sounds.contains(LJSND.SPAWN))) {
          v[player].hideNext = (v[player].field.nPieces > 7);
          v[player].frontDirty.dirtyNext = true;
        }

        // five, four, three, two, one
        int curCountdown = ctl.countdown;
        if (p.gimmick == LJGM.ULTRA && p.gameTime >= 10500) {
          curCountdown = (int)(10859 - p.gameTime) / 60;
        } else if (p.gimmick == LJGM.BTYPE) {
          curCountdown = 40 - p.lines;
        } else if (p.gimmick == LJGM.BABY) {
          curCountdown = (309 - v[player].control.presses) / 10;
        } else if (p.gimmick == LJGM.DRILL && (p.sounds.contains(LJSND.LINE))) {
          int line = Lockjaw.bfffo(p.tempRows);
          if (line < curCountdown)
          curCountdown = line;
        }

        // we have to wait for the new piece to come out
        // so that the score is credited properly
        if (curCountdown <= 0
            && (p.state == LJState.NEW_PIECE
                || p.state == LJState.FALLING
                || p.state == LJState.LANDED)) {
          p.state = LJState.GAMEOVER;
        }

        playSoundEffects(v[player], p.sounds, curCountdown);
        ctl.countdown = curCountdown;

        // Update speedometer
        if (p.sounds.contains(LJSND.LOCK)) {
          for (int i = LJView.N_SPEED_METER_PIECES - 2; i >= 0; --i) {
            v[player].lockTime[i + 1] = v[player].lockTime[i];
          }
          v[player].lockTime[0] = (int)p.gameTime;
          if (v[player].nLockTimes < LJView.N_SPEED_METER_PIECES) {
            ++v[player].nLockTimes;
          }
          v[player].frontDirty.dirtyScore();
        }

        // If the piece was just spawned, move the trail to the piece's
        // starting position and redraw next pieces.
        if (p.sounds.contains(LJSND.SPAWN) || p.sounds.contains(LJSND.HOLD)) {
          v[player].trailY = p.y;
          v[player].frontDirty.dirtyNext();
        }
      }

      ++lastTime;
    }

    for (int player = 0; player < nPlayers; ++player) {
      final LJField p = v[player].field;
      if (p.state == LJState.GAMEOVER && v[player].hidePF) {
        v[player].hidePF = false;
        v[player].backDirty.add((1 << LJ_PF_VIS_HT) - 1);
      }

      updField(v[player], v[player].backDirty);
      v[player].frontDirty.add(v[player].backDirty);
      v[player].backDirty.clear();

      // If piece is falling or landed, and it wasn't just spawned,
      // draw the piece and its shadow.

      if (p.sounds.contains(LJSND.SPAWN) || p.sounds.contains(LJSND.HOLD)) {
        // piece was just spawned, so don't draw the piece
      }
      // Otherwise, if the piece is falling or landed, draw it.
      else if (p.state == LJState.FALLING || p.state == LJState.LANDED
                || p.sounds.contains(LJSND.LOCK)) {
        if (v[player].hideShadow != LJSHADOW.NO_FALLING) {
          if (p.state == LJState.FALLING && v[player].hideShadow.isColored()) {
            drawShadow(v[player]);
          }
          drawFallingPiece(v[player]);
        }
      }

      ljBeginDraw(v[player], getTime() - lastTime < 2);
      drawScore(v[player]);
      blitField(v[player]);
      ljEndDraw(v[player]);
    }
  }

/*
//#if WITH_REPLAY
  {
    int player = 0;
    if (v[player].control.replaySrc != null) {
      replayClose(v[player].control.replaySrc);
      v[player].control.replaySrc = null;
    }
    if (v[player].control.replayDst != null) {
      replayClose(v[player].control.replayDst);
      v[player].control.replayDst = null;
    }
  }
//#endif
*/
}

}
